package de.lmu.mvs.lerngruppenfinder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import de.lmu.mvs.lerngruppenfinder.interests.InterestTree;
import de.lmu.mvs.lerngruppenfinder.utils.Constants;
import de.lmu.mvs.lerngruppenfinder.utils.FileApi;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector.ServerConnectorListener;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector.ServerError;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

/**
 * Activity displayes all groups in a given radius
 * 
 * FIXME show only subscribed groups
 * 
 * @author Christopher Gebhardt
 * @date 21.06.2014
 *
 */
public class GroupsMapActivity extends FragmentActivity {

	private static final String TAG = GroupsMapActivity.class.getSimpleName();

	private GoogleMap mMap;

	private HashMap<Marker, JsonObject> mMarkerMap = new HashMap<Marker, JsonObject>();

	private LocationManager mLocationManager;

	private JsonValue jsonGroups = null;

	private JsonValue jsonUserInterests = null;

	private boolean[] preloaderSuccess;
	private final int prelaodAmaount=2;

	/*
	 * Listen to location updates from location manager
	 */
	LocationListener mLocationListener = new LocationListener() {

		public void onLocationChanged(Location location) {
			if(location == null){
				Log.w(TAG, "Invalid location received.");
				return;
			}

			Log.d(TAG, "Location changed to: "+ location.getLatitude() + " | " + location.getLongitude());
			updateMap(location);

			if(jsonGroups == null){
				getNearbyGroups(location);
				getUserInterests();
			}
		}

		public void onStatusChanged(String provider, int status, Bundle extras) { }

		public void onProviderEnabled(String provider) { }

		public void onProviderDisabled(String provider) { }
	};

	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB){
			getActionBar().setDisplayHomeAsUpEnabled(true);
		}

		preloaderSuccess = new boolean[prelaodAmaount];
		for (int i=0;i<preloaderSuccess.length;i++){
			preloaderSuccess[i]=false;
		}

		setContentView(R.layout.activity_groups_map);

		mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

		mMap = ((SupportMapFragment) getSupportFragmentManager()
				.findFragmentById(R.id.map)).getMap();

		if(mMap != null){
			mMap.getUiSettings().setCompassEnabled(true);
			mMap.getUiSettings().setZoomControlsEnabled(true);
			mMap.getUiSettings().setMyLocationButtonEnabled(true);
			mMap.setMyLocationEnabled(true);

			mMap.setOnMarkerClickListener(new OnMarkerClickListener() {

				@Override
				public boolean onMarkerClick(Marker marker) {
					try {
						String groupId = mMarkerMap.get(marker).get(Constants.JSON_ID).asString();
						Intent groupDetailIntent = new Intent(getBaseContext(), GroupDetailActivity.class);
						groupDetailIntent.putExtra("id", Integer.parseInt(groupId));
						startActivity(groupDetailIntent);

					} catch(UnsupportedOperationException e){
						Log.e(TAG, e.getLocalizedMessage());
					} catch(NumberFormatException e){
						Log.e(TAG, e.getLocalizedMessage());
					}
					return false;
				}
			});

		} else {
			Toast.makeText(getBaseContext(), "Update or install latest google play services", Toast.LENGTH_LONG).show();
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case android.R.id.home:
			onBackPressed();
			return true;
		case R.id.action_logout:
        	FileApi.deleteLoginCredentials();
        	startActivity(new Intent(this, MainActivity.class));
        	finish();
        	return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	private void updateMap(Location location) {
		if(mMap != null){
			CameraPosition cameraPosition = new CameraPosition.Builder()
			.target(new LatLng(location.getLatitude(), location.getLongitude()))   
			.zoom(Constants.DEFAULT_MAP_ZOOM).tilt(Constants.MAP_CAMERA_TILT).build();
			mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
		}
	}

	/*
	 * FIXME showing all nearby groups now. Maybe only show subscribed
	 */
	private void getNearbyGroups(Location location) {
		Log.d(TAG, "Try to get nearby locations");

		if((jsonGroups = FileApi.readJsonFromStorage("groups", this)) != null){
			preloaderSuccess[0]=true;
			checkPreLoaders();
		} else {
			ServerConnector.getGroupsInRadius(new ServerConnectorListener<JsonArray>() {

				@Override
				public void requestFinished(JsonArray json) {
					if(json.size() < 1){
						Toast.makeText(getBaseContext(), R.string.toast_warning_no_nearby_groups_found, Toast.LENGTH_LONG).show();
					} else {
						jsonGroups = json;

						preloaderSuccess[0]=true;
						checkPreLoaders();
					}
				}

				@Override
				public void requestError(ServerError error) {
					Log.e(TAG, error.getErrorMessage());
				}
			}, location.getLatitude(), location.getLongitude(), Constants.GROUP_UPDATE_RADIUS);
		}
	}

	private void getUserInterests(){
		if((jsonUserInterests = FileApi.readJsonFromStorage(Constants.USER_INTERESTS, this)) != null){
			preloaderSuccess[1]=true;
			checkPreLoaders();
		} else {
			ServerConnector.getUserInterests(new ServerConnectorListener<JsonArray>() {

				@Override
				public void requestFinished(JsonArray json) {
					jsonUserInterests = json;

					preloaderSuccess[1]=true;
					checkPreLoaders();
				}

				@Override
				public void requestError(ServerError error) {
					Log.e("Login", error.getErrorMessage());
				}
			}, FileApi.readLoginCredentials().id);
		}
	}

	private void parseJson(){
		JsonArray interests = FileApi.readJsonFromStorage("interests", GroupsMapActivity.this).asArray();
		InterestTree tree = null;
		if(interests != null){
			tree = new InterestTree(interests, jsonUserInterests.asArray());
		}

		for (JsonValue jsonValue : jsonGroups.asArray()) {
			try {
				String lat = jsonValue.asObject().get(Constants.JSON_LATITUDE).asString();
				String lon = jsonValue.asObject().get(Constants.JSON_LONGITUDE).asString();
				String name = jsonValue.asObject().get(Constants.JSON_GROUP_NAME).asString();
				int interestId = Integer.parseInt(jsonValue.asObject().get(Constants.JSON_INTEREST).asString());

				if(tree != null && tree.find(interestId) != null){
					mMarkerMap.put(
							setMarker(new LatLng(Double.parseDouble(lat), Double.parseDouble(lon)), name),
							jsonValue.asObject()
							);
				} else if(tree == null) {
					mMarkerMap.put(
							setMarker(new LatLng(Double.parseDouble(lat), Double.parseDouble(lon)), name),
							jsonValue.asObject()
							);
				}
			} catch(UnsupportedOperationException e){
				Log.e(TAG, jsonGroups.toString());
			} catch(NumberFormatException e){
				Log.e(TAG, jsonGroups.toString());
			}
		}
	}

	private Marker setMarker(LatLng location, String name) {
		Marker marker = mMap.addMarker(
				new MarkerOptions()
				.position(location)
				.title(name));
		return marker;
	}

	@Override
	protected void onResume() {
		super.onResume();
		if(mLocationManager != null){
			mLocationManager.requestLocationUpdates(
					LocationManager.PASSIVE_PROVIDER, 
					Constants.LOCATION_UPDATE_TIME, 
					Constants.LOCATION_UPDATE_DISTANCE, 
					mLocationListener);
			Log.d(TAG, "Locationmanager initialised");
		}
	}

	@Override
	protected void onPause() {
		super.onPause();
		if(mLocationManager != null){
			mLocationManager.removeUpdates(mLocationListener);
			Log.d(TAG, "Locationmanager stopped");
		}
	}

	private void checkPreLoaders(){
		for (int i=0;i<preloaderSuccess.length;i++){
			if (preloaderSuccess[i]==false){
				return;
			}
		}
		parseJson();
	}
}

